home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / UTIL / PL 2.0 SupplementDoc Folder.sit / PL 2.0 SupplementDoc Folder / Documentation / Chapter 03. Scope and Extent < prev    next >
Lisp/Scheme  |  1995-03-27  |  15KB  |  323 lines

  1. Common Lisp the Language, 2nd Edition
  2. -------------------------------------------------------------------------------
  3.  
  4. 3. Scope and Extent
  5.  
  6. In describing various features of the Common Lisp language, the notions of
  7. scope and extent are frequently useful. These notions arise when some object or
  8. construct must be referred to from some distant part of a program. Scope refers
  9. to the spatial or textual region of the program within which references may
  10. occur. Extent refers to the interval of time during which references may occur.
  11.  
  12. As a simple example, consider this program:
  13.  
  14. (defun copy-cell (x) (cons (car x) (cdr x)))
  15.  
  16. The scope of the parameter named x is the body of the defun form. There is no
  17. way to refer to this parameter from any other place but within the body of the
  18. defun. Similarly, the extent of the parameter x (for any particular call to
  19. copy-cell) is the interval from the time the function is invoked to the time it
  20. is exited. (In the general case, the extent of a parameter may last beyond the
  21. time of function exit, but that cannot occur in this simple case.)
  22.  
  23. Within Common Lisp, a referenceable entity is established by the execution of
  24. some language construct, and the scope and extent of the entity are described
  25. relative to the construct and the time (during execution of the construct) at
  26. which the entity is established. For the purposes of this discussion, the term
  27. ``entity'' refers not only to Common Lisp data objects, such as symbols and
  28. conses, but also to variable bindings (both ordinary and special), catchers,
  29. and go targets. It is important to distinguish between an entity and a name for
  30. the entity. In a function definition such as
  31.  
  32. (defun foo (x y) (* x (+ y 1)))
  33.  
  34. there is a single name, x, used to refer to the first parameter of the
  35. procedure whenever it is invoked; however, a new binding is established on
  36. every invocation. A binding is a particular parameter instance. The value of a
  37. reference to the name x depends not only on the scope within which it occurs
  38. (the one in the body of foo in the example occurs in the scope of the function
  39. definition's parameters) but also on the particular binding or instance
  40. involved. (In this case, it depends on the invocation during which the
  41. reference is made). More complicated examples appear at the end of this
  42. chapter.
  43.  
  44. There are a few kinds of scope and extent that are particularly useful in
  45. describing Common Lisp:
  46.  
  47.    *  Lexical scope. Here references to the established entity can occur only
  48.      within certain program portions that are lexically (that is, textually)
  49.      contained within the establishing construct. Typically the construct will
  50.      have a part designated the body, and the scope of all entities established
  51.      will be (or include) the body.
  52.  
  53.      Example: the names of parameters to a function normally are lexically
  54.      scoped.
  55.  
  56.    *  Indefinite scope. References may occur anywhere, in any program.
  57.  
  58.    *  Dynamic extent. References may occur at any time in the interval between
  59.      establishment of the entity and the explicit disestablishment of the
  60.      entity. As a rule, the entity is disestablished when execution of the
  61.      establishing construct completes or is otherwise terminated. Therefore
  62.      entities with dynamic extent obey a stack-like discipline, paralleling the
  63.      nested executions of their establishing constructs.
  64.  
  65.      Example: the with-open-file construct opens a connection to a file and
  66.      creates a stream object to represent the connection. The stream object has
  67.      indefinite extent, but the connection to the open file has dynamic extent:
  68.      when control exits the with-open-file construct, either normally or
  69.      abnormally, the stream is automatically closed.
  70.  
  71.      Example: the binding of a ``special'' variable has dynamic extent.
  72.  
  73.    *  Indefinite extent. The entity continues to exist as long as the
  74.      possibility of reference remains. (An implementation is free to destroy
  75.      the entity if it can prove that reference to it is no longer possible.
  76.      Garbage collection strategies implicitly employ such proofs.)
  77.  
  78.      Example: most Common Lisp data objects have indefinite extent.
  79.  
  80.      Example: the bindings of lexically scoped parameters of a function have
  81.      indefinite extent. (By contrast, in Algol the bindings of lexically scoped
  82.      parameters of a procedure have dynamic extent.) The function definition
  83.  
  84.      (defun compose (f g)
  85.        #'(lambda (x)
  86.            (funcall f (funcall g x))))
  87.  
  88.      when given two arguments, immediately returns a function as its value. The
  89.      parameter bindings for f and g do not disappear because the returned
  90.      function, when called, could still refer to those bindings. Therefore
  91.  
  92.      (funcall (compose #'sqrt #'abs) -9.0)
  93.  
  94.      produces the value 3.0. (An analogous procedure would not necessarily work
  95.      correctly in typical Algol implementations or, for that matter, in most
  96.      Lisp dialects.)
  97.  
  98. In addition to the above terms, it is convenient to define dynamic scope to
  99. mean indefinite scope and dynamic extent. Thus we speak of ``special''
  100. variables as having dynamic scope, or being dynamically scoped, because they
  101. have indefinite scope and dynamic extent: a special variable can be referred to
  102. anywhere as long as its binding is currently in effect.
  103.  
  104. [change_begin]
  105. The term ``dynamic scope'' is a misnomer. Nevertheless it is both traditional
  106. and useful.
  107. [change_end]
  108.  
  109. The above definitions do not take into account the possibility of shadowing.
  110. Remote reference of entities is accomplished by using names of one kind or
  111. another. If two entities have the same name, then the second may shadow the
  112. first, in which case an occurrence of the name will refer to the second and
  113. cannot refer to the first.
  114.  
  115. In the case of lexical scope, if two constructs that establish entities with
  116. the same name are textually nested, then references within the inner construct
  117. refer to the entity established by the inner one; the inner one shadows the
  118. outer one. Outside the inner construct but inside the outer one, references
  119. refer to the entity established by the outer construct. For example:
  120.  
  121. (defun test (x z)
  122.   (let ((z (* x 2))) (print z))
  123.   z)
  124.  
  125. The binding of the variable z by the let construct shadows the parameter
  126. binding for the function test. The reference to the variable z in the print
  127. form refers to the let binding. The reference to z at the end of the function
  128. refers to the parameter named z.
  129.  
  130. In the case of dynamic extent, if the time intervals of two entities overlap,
  131. then one interval will necessarily be nested within the other one. This is a
  132. property of the design of Common Lisp.
  133.  
  134. -------------------------------------------------------------------------------
  135. Implementation note: Behind the assertion that dynamic extents nest properly is
  136. the assumption that there is only a single program or process. Common Lisp does
  137. not address the problems of multiprogramming (timesharing) or multiprocessing
  138. (more than one active processor) within a single Lisp environment. The
  139. documentation for implementations that extend Common Lisp for multiprogramming
  140. or multiprocessing should be very clear on what modifications are induced by
  141. such extensions to the rules of extent and scope. Implementors should note that
  142. Common Lisp has been carefully designed to allow special variables to be
  143. implemented using either the ``deep binding'' technique or the ``shallow
  144. binding'' technique, but the two techniques have different semantic and
  145. performance implications for multiprogramming and multiprocessing.
  146. -------------------------------------------------------------------------------
  147.  
  148. A reference by name to an entity with dynamic extent will always refer to the
  149. entity of that name that has been most recently established that has not yet
  150. been disestablished. For example:
  151.  
  152. (defun fun1 (x)
  153.   (catch 'trap (+ 3 (fun2 x))))
  154.  
  155. (defun fun2 (y)
  156.   (catch 'trap (* 5 (fun3 y))))
  157.  
  158. (defun fun3 (z)
  159.   (throw 'trap z))
  160.  
  161. Consider the call (fun1 7). The result will be 10. At the time the throw is
  162. executed, there are two outstanding catchers with the name trap: one
  163. established within procedure fun1, and the other within procedure fun2. The
  164. latter is the more recent, and so the value 7 is returned from the catch form
  165. in fun2. Viewed from within fun3, the catch in fun2 shadows the one in fun1.
  166. Had fun2 been defined as
  167.  
  168. (defun fun2 (y)
  169.   (catch 'snare (* 5 (fun3 y))))
  170.  
  171. then the two catchers would have different names, and therefore the one in fun1
  172. would not be shadowed. The result would then have been 7.
  173.  
  174. As a rule, this book simply speaks of the scope or extent of an entity; the
  175. possibility of shadowing is left implicit.
  176.  
  177. The important scope and extent rules in Common Lisp follow:
  178.  
  179.    *  Variable bindings normally have lexical scope and indefinite extent.
  180.  
  181. [change_begin]
  182.  
  183.    *  Variable bindings for which there is a dynamic-extent declaration also
  184.      have lexical scope and indefinite extent, but objects that are the values
  185.      of such bindings may have dynamic extent. (The declaration is the
  186.      programmer's guarantee that the program will behave correctly even if
  187.      certain of the data objects have only dynamic extent rather than the usual
  188.      indefinite extent.)
  189.  
  190.    *  Bindings of variable names to symbol macros by symbol-macrolet have
  191.      lexical scope and indefinite extent.
  192.  
  193. [change_end]
  194.  
  195.    *  Variable bindings that are declared to be special have dynamic scope
  196.      (indefinite scope and dynamic extent).
  197.  
  198. [change_begin]
  199.  
  200.    *  Bindings of function names established, for example, by flet and labels
  201.      have lexical scope and indefinite extent.
  202.  
  203.    *  Bindings of function names for which there is a dynamic-extent
  204.      declaration also have lexical scope and indefinite extent, but function
  205.      objects that are the values of such bindings may have dynamic extent.
  206.  
  207.    *  Bindings of function names to macros as established by macrolet have
  208.      lexical scope and indefinite extent.
  209.  
  210.    *  Condition handlers and restarts have dynamic scope (see chapter 29).
  211.  
  212. [change_end]
  213.  
  214.    *  A catcher established by a catch or unwind-protect special form has
  215.      dynamic scope.
  216.  
  217.    *  An exit point established by a block construct has lexical scope and
  218.      dynamic extent. (Such exit points are also established by do, prog, and
  219.      other iteration constructs.)
  220.  
  221.    *  The go targets established by a tagbody, named by the tags in the
  222.      tagbody, and referred to by go have lexical scope and dynamic extent.
  223.      (Such go targets may also appear as tags in the bodies of do, prog, and
  224.      other iteration constructs.)
  225.  
  226.    *  Named constants such as nil and pi have indefinite scope and indefinite
  227.      extent.
  228.  
  229. The rules of lexical scoping imply that lambda-expressions appearing in the
  230. function construct will, in general, result in ``closures'' over those
  231. non-special variables visible to the lambda-expression. That is, the function
  232. represented by a lambda-expression may refer to any lexically apparent
  233. non-special variable and get the correct value, even if the construct that
  234. established the binding has been exited in the course of execution. The compose
  235. example shown earlier in this chapter provides one illustration of this. The
  236. rules also imply that special variable bindings are not ``closed over'' as they
  237. may be in certain other dialects of Lisp.
  238.  
  239. Constructs that use lexical scope effectively generate a new name for each
  240. established entity on each execution. Therefore dynamic shadowing cannot occur
  241. (though lexical shadowing may). This is of particular importance when dynamic
  242. extent is involved. For example:
  243.  
  244. (defun contorted-example (f g x)
  245.   (if (= x 0)
  246.       (funcall f)
  247.       (block here
  248.          (+ 5 (contorted-example g
  249.                                  #'(lambda ()
  250.                                      (return-from here 4))
  251.                                  (- x 1))))))
  252.  
  253. Consider the call (contorted-example nil nil 2). This produces the result 4.
  254. During the course of execution, there are three calls on contorted-example,
  255. interleaved with two establishments of blocks:
  256.  
  257. (contorted-example nil nil 2)
  258.  
  259.   (block here   ...)
  260.  
  261.     (contorted-example nil #'(lambda () (return-from here   4)) 1)
  262.  
  263.       (block here   ...)
  264.  
  265.         (contorted-example #'(lambda () (return-from here   4))
  266.                            #'(lambda () (return-from here   4))
  267.                            0)
  268.           (funcall f)
  269.                 where f => #'(lambda () (return-from here   4))
  270.  
  271.             (return-from here   4)
  272.  
  273. At the time the funcall is executed there are two block exit points
  274. outstanding, each apparently named here. In the trace above, these exit points
  275. are distinguished for expository purposes by subscripts. The return-from form
  276. executed as a result of the funcall operation refers to the outer outstanding
  277. exit point (here  ), not the inner one (here  ). This is a consequence of the
  278. rules of lexical scoping: it refers to that exit point textually visible at the
  279. point of execution of the function construct (here abbreviated by the #'
  280. syntax) that resulted in creation of the function object actually invoked by
  281. the funcall.
  282.  
  283. If, in this example, one were to change the form (funcall f) to (funcall g),
  284. then the value of the call (contorted-example nil nil 2) would be 9. The value
  285. would change because the funcall would cause the execution of (return-from here
  286.    4), thereby causing a return from the inner exit point (here  ). When that
  287. occurs, the value 4 is returned from the middle invocation of
  288. contorted-example, 5 is added to that to get 9, and that value is returned from
  289. the outer block and the outermost call to contorted-example. The point is that
  290. the choice of exit point returned from has nothing to do with its being
  291. innermost or outermost; rather, it depends on the lexical scoping information
  292. that is effectively packaged up with a lambda-expression when the function
  293. construct is executed.
  294.  
  295. This function contorted-example works only because the function named by f is
  296. invoked during the extent of the exit point. Block exit points are like
  297. non-special variable bindings in having lexical scope, but they differ in
  298. having dynamic extent rather than indefinite extent. Once the flow of execution
  299. has left the block construct, the exit point is disestablished. For example:
  300.  
  301. (defun illegal-example ()
  302.   (let ((y (block here #'(lambda (z) (return-from here z)))))
  303.     (if (numberp y) y (funcall y 5))))
  304.  
  305. One might expect the call (illegal-example) to produce 5 by the following
  306. incorrect reasoning: the let statement binds the variable y to the value of the
  307. block construct; this value is a function resulting from the lambda-expression.
  308. Because y is not a number, it is invoked on the value 5. The return-from should
  309. then return this value from the exit point named here, thereby exiting from the
  310. block again and giving y the value 5 which, being a number, is then returned as
  311. the value of the call to illegal-example.
  312.  
  313. The argument fails only because exit points are defined in Common Lisp to have
  314. dynamic extent. The argument is correct up to the execution of the return-from.
  315. The execution of the return-from is an error, however, not because it cannot
  316. refer to the exit point, but because it does correctly refer to an exit point
  317. and that exit point has been disestablished.
  318.  
  319.  
  320.  
  321.  
  322.  
  323.